home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / et / et3_0-a1.lha / et3 / src / Storage.C < prev    next >
C/C++ Source or Header  |  1992-08-19  |  10KB  |  471 lines

  1. #ifdef __GNUG__
  2. #pragma implementation
  3. #endif
  4.  
  5. #include "Storage.h"
  6.  
  7. #include "CLib.h"
  8. #include "String.h"
  9. #include "Error.h"
  10. #include "Object.h"
  11. #include "ObjectTable.h"
  12. #include "Math.h"
  13.  
  14. #define MEM_MAGIC ((char)0xAB)
  15. #define MEM_STAT
  16. //#define MEM_CHECKOBJECTPOINTERS
  17.  
  18. #ifdef MEM_CHECKOBJECTPOINTERS
  19. #   define CheckObjPtr(name, p) ObjectTable::CheckPtrAndWarn(name, p);
  20. #else
  21. #   define CheckObjPtr(name, p) p
  22. #endif
  23.  
  24. const int cMemPoolSize  =   100,
  25.       cObjMaxSize   =   1024;       
  26.  
  27. u_long Storage_lastobj, Storage_lastobjend;
  28. bool Storage_proto;
  29.  
  30. static bool died;
  31. static size_t maxA;
  32. static FreeHookFun storageFreeHook;
  33. static void *storageFreeHookData;
  34.  
  35. //---- Pool for a specific size ------------------------------------------------
  36.  
  37. struct FreeNode {
  38.     class FreeNode *next;
  39. };
  40.  
  41. class Chunk {
  42. public:
  43.     struct Chunk *next;
  44.     char *storage;
  45. public:
  46.     Chunk(Chunk *n, size_t size)
  47.     { next= n; storage= new char[size]; }
  48.     ~Chunk()
  49.     { SafeDelete(storage); }
  50. };
  51.  
  52. class MemPool {
  53. public:
  54. friend class Storage;
  55.     struct Chunk *chunks;
  56.     struct FreeNode *freeList;
  57.     int lastIndex, chunkSize, allocated, recycled, freed;
  58.     size_t objSize;
  59. public:
  60.     MemPool(size_t objSize);
  61.     ~MemPool();
  62.     void *Alloc();
  63.     void Free(void *);
  64.     int nchunks();
  65. };
  66.  
  67. static MemPool *pools[cObjMaxSize];
  68.  
  69. #ifdef MEM_STAT
  70.  
  71.     static bool gMemStatistics;
  72.     static int ASizes[cObjMaxSize];
  73.     static int FSizes[cObjMaxSize];
  74.     static int totalA, totalF;
  75.     static void *ttt[1000];
  76.     static int tt, mem_size= -1, mem_ix= -1;
  77.     
  78.     void EnterStat(size_t size, void *p)
  79.     {
  80.     if (gMemStatistics && size == mem_size) {
  81.         if (tt == mem_ix)
  82.         CLib::Abort();
  83.         ttt[tt++]= p;
  84.     }
  85.     maxA= Math::Max(maxA, size);
  86.     if (size >= cObjMaxSize)
  87.         ASizes[cObjMaxSize-1]++;
  88.     else
  89.         ASizes[size]++;
  90.     totalA+= size;
  91.     }
  92.     
  93.     void RemoveStat(size_t size, void *vp)
  94.     {
  95.     if (gMemStatistics && size == mem_size) {
  96.         for (int i= 0; i < tt; i++)
  97.         if (ttt[i] == vp) {
  98.             ttt[i]= 0;
  99.             break;
  100.         }
  101.     }
  102.     if (size >= cObjMaxSize)
  103.         FSizes[cObjMaxSize-1]++;
  104.     else
  105.         FSizes[size]++;
  106.     totalF+= size;
  107.     }
  108.     
  109. #else
  110.  
  111. #   define EnterStat(s, p) maxA= Math::Max(maxA, s);
  112. #   define RemoveStat(s, p)
  113.  
  114. #endif
  115.  
  116. static bool FreeFromPool(void *vp)
  117. {
  118.     register int i;
  119.     register Chunk *p;
  120.     register MemPool *mp;
  121.  
  122.     for (i= 0; i < cObjMaxSize; i++) {
  123.     if (mp= pools[i]) {
  124.         for (p= mp->chunks; p; p= p->next) {
  125.         if (vp >= (void*)p->storage
  126.                     && vp < (void*)(p->storage + mp->chunkSize)) {
  127.             mp->Free(vp);
  128.             return TRUE;
  129.         }
  130.         }
  131.     }
  132.     }
  133.     return FALSE;
  134. }
  135.  
  136. /*
  137. inline size_t storage_size(char *ptr)
  138.     return ((int*)ptr)[-1];
  139. }
  140. */
  141.  
  142. #define storage_size(ptr) ((size_t)(((int*)ptr)[-1]))
  143.  
  144. //---- Pool for a specific size ------------------------------------------------
  145.  
  146. MemPool::MemPool(size_t osize)
  147. {
  148.     objSize= osize;
  149.     chunkSize= cMemPoolSize * objSize;
  150.     chunks= 0;
  151.     lastIndex= cMemPoolSize; // force allocation of a new chunk
  152.     freeList= 0;
  153.     allocated= recycled= freed= 0;
  154. }
  155.  
  156. MemPool::~MemPool()
  157. {
  158.     Chunk *p, *lp;
  159.  
  160.     for (p= chunks; p; p= lp) {
  161.     lp= p->next;
  162.     delete p;
  163.     }
  164. }
  165.  
  166. int MemPool::nchunks()
  167. {
  168.     int n;
  169.     Chunk *p;
  170.     
  171.     for (n= 0, p= chunks; p; p= p->next, n++)
  172.     ;
  173.     return n;
  174. }
  175.  
  176. void *MemPool::Alloc()
  177. {
  178.     allocated++;
  179.     if (freeList) {
  180.     recycled++;
  181.     FreeNode *tmp= freeList;
  182.     freeList= freeList->next;
  183.     return (void*)tmp;
  184.     }
  185.     if (lastIndex >= cMemPoolSize) { // need new chunk
  186.     chunks= new Chunk(chunks, chunkSize);
  187.     lastIndex= 0;
  188.     }
  189.     return (void*) &chunks->storage[lastIndex++ * objSize];
  190. }
  191.  
  192. void MemPool::Free(void *op)
  193. {
  194.     if (storageFreeHook)
  195.     storageFreeHook(storageFreeHookData, op, objSize);
  196.  
  197.     for (Chunk *p= chunks; p; p= p->next) {
  198.     if (op >= (void*)p->storage && op <  (void*)(p->storage + chunkSize)) {
  199.         memset(op, 0, objSize);
  200.         FreeNode *fn= (FreeNode*)op;
  201.         fn->next= freeList;
  202.         freeList= fn;
  203.         freed++;
  204.         return;
  205.     }
  206.     }
  207.     fprintf(stderr, "Fatal in MemPool::Free: object to delete not found in pool %d\n", objSize);
  208.     fflush(stderr);
  209.     CLib::Abort();
  210. }
  211.  
  212. //---- Storage -----------------------------------------------------------------
  213.  
  214. void* operator new(size_t size)
  215. {
  216.     register int *sp;
  217.  
  218.     if (size < 0) {
  219.     fprintf(stderr, "Fatal in operator new: size < 0\n");
  220.     fflush(stderr);
  221.     CLib::Abort();
  222.     }
  223. #ifdef MEM_MAGIC
  224.     sp= (int*) CLib::CAlloc(size + sizeof(int) + sizeof(char), sizeof(char));
  225. #else
  226.     sp= (int*) CLib::CAlloc(size + sizeof(int), sizeof(char));
  227. #endif
  228.     if (sp == 0) {
  229.     fprintf(stderr, "Fatal in operator new: storage exhausted\n");
  230.     fflush(stderr);
  231.     CLib::Abort();
  232.     }
  233.     sp[0]= size;
  234. #ifdef MEM_MAGIC
  235.     *((char*)sp+size+sizeof(int))= MEM_MAGIC;
  236. #endif
  237.     EnterStat(size, &sp[1]);
  238.     return CheckObjPtr("new", &sp[1]);
  239. }
  240.  
  241. void operator delete(void* ptr)
  242. {
  243.     Storage_lastobj= Storage_lastobjend= 0;
  244.     Storage_proto= FALSE;
  245.     if (ptr) {
  246.     (void) CheckObjPtr("free", ptr);
  247.     if (!died && FreeFromPool(ptr))
  248.         return;
  249.     int size= storage_size((char*)ptr);
  250.     if (size < 0 || size > maxA) {
  251.         fprintf(stderr, "Fatal in operator delete: unreasonable size (%d)\n", size);
  252.         fflush(stderr);
  253.         CLib::Abort();
  254.     }
  255.     RemoveStat(size, ptr);
  256.     if (storageFreeHook) 
  257.         storageFreeHook(storageFreeHookData, ptr, size);
  258.     ptr= (char*)ptr - sizeof(int);
  259.     size+=sizeof(int);
  260. #ifdef MEM_MAGIC
  261.     if (*((char*)ptr+size) != MEM_MAGIC) {
  262.         fprintf(stderr, "Fatal in operator delete: storage area overwritten\n");
  263.         fflush(stderr);
  264.         CLib::Abort();
  265.     }
  266.     size+= sizeof(char);
  267. #endif
  268.     memset(ptr, 0, size);
  269.     CLib::ErrNo= 0;
  270.     CLib::Free((char*) ptr);
  271.     if (CLib::ErrNo != 0) {
  272.         perror("operator delete");
  273.         CLib::Abort();
  274.     }
  275.     }
  276. }
  277.  
  278. void *Realloc(void *vp, size_t size)
  279. {
  280.     if (vp == 0)
  281.     return new char[size];
  282.     
  283.     int oldsize= storage_size((char*)vp);
  284.     if (size > oldsize) {
  285.     int *sp, sz= size;
  286.     char *ptr= (char*)vp, *cp;
  287.     
  288.     RemoveStat(oldsize, vp);
  289.     
  290. #ifdef MEM_MAGIC
  291.     sz+= sizeof(char);
  292. #endif
  293.     sp= (int*) CLib::ReAlloc((char*) (ptr - sizeof(int)), sz+sizeof(int));
  294.     cp= (char*) &sp[1];
  295.     EnterStat(size, &sp[1]);
  296.     
  297. #ifdef MEM_MAGIC
  298.     if (cp[oldsize] != MEM_MAGIC) {
  299.         fprintf(stderr, "Fatal in Realloc: storage area overwritten\n");
  300.         fflush(stderr);
  301.         CLib::Abort();
  302.     }
  303.     *((char*)sp+size+sizeof(int))= MEM_MAGIC;
  304. #endif
  305.     memset(&cp[oldsize], 0, size-oldsize);
  306.     sp[0]= size;
  307.     return CheckObjPtr("Realloc", cp);
  308.     }
  309.     return vp;
  310. }
  311.  
  312. void *Storage::Alloc(size_t sz)
  313. {
  314.     return new char[sz];
  315. }
  316.  
  317. void *Storage::Alloc(size_t sz, const char*, int)
  318. {
  319.     return new char[sz];
  320. }
  321.  
  322. void Storage::Free(void *vp)
  323. {
  324.     delete vp;
  325. }
  326.  
  327. void *Storage::ChunkAlloc(size_t sz)
  328. {
  329.     if (died || sz >= cObjMaxSize)
  330.     return (void*) new char[sz];
  331.     MemPool *mp= pools[sz];
  332.     if (mp == 0)
  333.     mp= pools[sz]= new MemPool(sz);
  334.     return CheckObjPtr("Storage::ChunkAlloc", mp->Alloc());
  335. }
  336.  
  337. void Storage::ChunkFree(void *vp)
  338. {
  339.     register int i;
  340.     register Chunk *p;
  341.     register MemPool *mp;
  342.  
  343.     for (i= 0; i < cObjMaxSize; i++) {
  344.     if (mp= pools[i]) {
  345.         for (p= mp->chunks; p; p= p->next) {
  346.         if (vp >= (void*)p->storage
  347.                     && vp < (void*)(p->storage + mp->chunkSize)) {
  348.             mp->Free(vp);
  349.             return;
  350.         }
  351.         }
  352.     }
  353.     }
  354. }
  355.  
  356. void *Storage::ObjectChunkAlloc(size_t sz)
  357. {
  358.     if (died || sz >= cObjMaxSize)
  359.     return (void*) new char[sz];
  360.     MemPool *mp= pools[sz];
  361.     if (mp == 0) 
  362.     mp= pools[sz]= new MemPool(sz);
  363.     return CheckObjPtr("Storage::ObjectChunkAlloc", mp->Alloc());
  364. }
  365.  
  366. void Storage::ObjectChunkFree(void *vp)
  367. {
  368.     delete vp;
  369. }
  370.  
  371. void *Storage::ObjectAlloc(size_t sz)
  372. {
  373.     Storage_proto= FALSE;
  374.     Storage_lastobj= (u_long) new char[sz];
  375.     Storage_lastobjend= Storage_lastobj + sz;
  376.     return (void*) Storage_lastobj;
  377. }
  378.  
  379. void *Storage::ObjectAlloc(size_t sz, const char*, int)
  380. {
  381.     Storage_proto= FALSE;
  382.     Storage_lastobj= (u_long) new char[sz];
  383.     Storage_lastobjend= Storage_lastobj + sz;
  384.     return (void*) Storage_lastobj;
  385. }
  386.  
  387. void Storage::ObjectFree(void *vp)
  388. {
  389.     delete vp;
  390. }
  391.  
  392. void *Storage::ReAlloc(void *vp, size_t sz)
  393. {
  394.     return ::Realloc(vp, sz);
  395. }
  396.  
  397. void Storage::SetFreeHook(FreeHookFun fh, void *data)
  398. {
  399.     storageFreeHook= fh;
  400.     storageFreeHookData= data;
  401. }
  402.  
  403. void Storage::Statistics()
  404. {
  405. #ifdef MEM_STAT
  406.     MemPool *fsp;
  407.     
  408.     if (!gMemStatistics)
  409.     return;
  410.     
  411.     if (totalA == totalF) {
  412.     fprintf(stderr, "no garbage left (total: %d)\n", totalA);
  413.     return;
  414.     }
  415.     
  416.     fprintf(stderr, "\n");
  417.     fprintf(stderr, "Mem statistics\n");
  418.     fprintf(stderr, "%7s%7s%7s%7s%7s%7s%7s%7s",
  419.     "size", "alloc", "free", "diff", "alloc", "recycl", "freed", "chunks\n");
  420.     fprintf(stderr, "=======================================================\n");
  421.     
  422.  
  423.     for (int i= 0; i < cObjMaxSize; i++) {
  424.     fsp= pools[i];
  425.     if (ASizes[i] != FSizes[i] || fsp)
  426.         fprintf(stderr, "%7d%7d%7d%7d", i, ASizes[i], FSizes[i],
  427.                             ASizes[i]-FSizes[i]);
  428.     if (fsp)
  429.         fprintf(stderr, "%7d%7d%7d%7d", fsp->allocated, 
  430.                     fsp->recycled, fsp->freed, fsp->nchunks());
  431.     if (ASizes[i] != FSizes[i] || fsp)
  432.         fprintf(stderr, "\n");
  433.     }
  434.  
  435.     if (totalA != totalF) {
  436.     fprintf(stderr, "-------------------------------------------------------\n");
  437.     fprintf(stderr, "total: %7d%7d%7d\n", totalA, totalF, totalA-totalF);
  438.     }
  439.  
  440.     if (mem_size != -1) {
  441.     fprintf(stderr, "-------------------------------------------------------\n");
  442.     for (i= 0; i < tt; i++)
  443.         if (ttt[i])
  444.         fprintf(stderr, "block %d of size %d not freed\n", i, mem_size);
  445.     }
  446.     fprintf(stderr, "=======================================================\n");
  447.     fprintf(stderr, "\n");
  448.     fflush(stderr);
  449. #endif
  450. }
  451.  
  452. void Storage::EnableStatistics(int size, int ix)
  453. {
  454. #ifdef MEM_STAT
  455.     mem_size= size;
  456.     mem_ix= ix;
  457.     gMemStatistics= TRUE;
  458. #endif
  459. }
  460.  
  461. void Storage::FreeAll()
  462. {
  463.     died= TRUE;
  464.     for (int i= 0; i < cObjMaxSize; i++)
  465.     SafeDelete(pools[i]);
  466.  
  467.     Statistics();
  468. }
  469.  
  470.